# Copyright (c) 2021 Presto Labs Pte. Ltd.
# Author: leon

import json
import datetime
import logging
import signal

from web3 import Web3
from absl import flags, app
from tornado.ioloop import IOLoop

FLAGS = flags.FLAGS

UNISWAP_V2_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'


class UniswapV2Strategy:
  def __init__(self, exit_after_min=None, logger=None):
    self._logger = logger or logging.getLogger('UniswapV2Strategy')
    self._ioloop = IOLoop.current()
    self._w3 = Web3(Web3.WebsocketProvider('ws://35.74.128.68:8545'))
    self._logger.info(self._w3.isConnected())
    self._contract = None

  def signal_handler(self, sig, frame):
    self._logger.warning('Caught signal: %s', sig)
    self._ioloop.add_callback_from_signal(self.on_exit)

  def register_exit(self, timedelta=None):
    if timedelta is None:
      self._ioloop.add_callback(self.on_exit)
    else:
      self._ioloop.add_timeout(timedelta, self.on_exit)

  def on_exit(self):
    self._ioloop.add_callback(self._ioloop.stop)

  def check_all_pairs(self):
    with open('IUniswapV2Factory.json') as abi_file:
      factory_abi = json.load(abi_file)['abi']
    factory_contract = self._w3.eth.contract(abi=factory_abi, address=UNISWAP_V2_FACTORY_ADDRESS)
    self._contract = factory_contract
    all_pairs_length = factory_contract.functions.allPairsLength().call()
    self._logger.info(all_pairs_length)

    with open('IUniswapV2Pair.json') as pair_abi_file:
      pair_abi = json.load(pair_abi_file)['abi']

    for i in range(1, all_pairs_length):
      pair_address = factory_contract.functions.allPairs(i).call()
      contract = self._w3.eth.contract(address=pair_address, abi=pair_abi)
      supply = contract.functions.totalSupply().call()
      print(pair_address, supply)

  # asynchronous defined function to loop
  # this loop sets up an event filter and is looking for new entires for the "PairCreated" event
  # this loop runs on a poll interval
  def log_loop(self, event_filter, poll_interval):
    events = event_filter.get_all_entries()
    for pair_created_event in events:
      print(Web3.toJSON(pair_created_event))
    self._ioloop.add_timeout(datetime.timedelta(seconds=poll_interval), self.log_loop, event_filter, poll_interval)

  def start(self):
    self.check_all_pairs()
    event_filter = self._contract.events.PairCreated.createFilter(fromBlock='latest')
    self.log_loop(event_filter, 1)
    self._ioloop.start()


def main(_):
  strategy = UniswapV2Strategy()
  strategy.register_exit(datetime.timedelta(minutes=FLAGS.exit_after_min))
  signal.signal(signal.SIGTERM, strategy.signal_handler)
  signal.signal(signal.SIGINT, strategy.signal_handler)
  strategy.start()


if __name__ == "__main__":
  flags.DEFINE_integer('exit_after_min', 60, 'exit_after_min')

  app.run(main)
